/**********************************************************************/
/**  Copyright (c) ECC labs. 2001-2002. All Rights Reserved.		 **/
/**********************************************************************/
/*
	binword.cpp
	Mark Papazyan

*/

#include "binlongw.h"


CBinLongWord::CBinLongWord(t_len k):n(k), weight(0)
{
	len=n/MOD;
	if(n!=len*MOD)
		len++;
	num=new t_src[len];

	for(t_cnt i=0; i<len; i++)
		num[i]=(t_src)0;
}


CBinLongWord::CBinLongWord(const CBinLongWord& t)
{
	num=new t_src[n=t.n];
	weight=t.weight;
	len=t.len;
	for(t_cnt i=0; i<len; i++)
		num[i]=t.num[i];
}


CBinLongWord::CBinLongWord(char* ch, t_cnt k):n(k),weight(0)
{
	t_cnt l=0;
	while(ch[l])l++;
	if(l>n)
		n=l;

	len=n/MOD;
	if(n!=len*MOD)
		len++;
	num=new t_src[len];

	for(t_cnt j=0; j<len; j++)
		num[j]=(t_src)0;

	for(t_cnt i=0; i<l; i++)
		if(ch[l-1-i]=='1')
			num[i/MOD]^=(I<<(i%MOD));
}


CBinLongWord::~CBinLongWord()
{
	delete[] num;
}


CBinLongWord& CBinLongWord::operator =(const CBinLongWord&t)
{
	if(this!=&t)
	{
		delete[] num;
		num=new t_src[n=t.n];
		len=t.len;
		weight=t.weight;
		for(t_cnt i=0; i<len; i++)
			num[i]=t.num[i];
	}
	return *this;
}


ostream& operator<<(ostream& out, CBinLongWord& a)
{
	for(t_cnt i=a.n-1; i>=0; i--)
		((a.num[i/MOD]>>(i%MOD))&I)?out<<'1':out<<'.';
	return out;
}

/*
istream& operator>>(istream& in, CBinLongWord& a)
{
	string s;
	cin>>s;
	t_cnt size=s.size();
	if(a.n<size)
		a.n=size;
	t_cnt pos=size-1;

	t_cnt len=size/MOD;
	if(a.n!=len*MOD)
		len++;

	if(len>a.len){
		a.len=len;
		delete[] a.num;
		a.num=new t_src[len];
	}
	
	for(t_cnt ii=0; ii<a.len; ii++)
			a.num[ii]=(I)0;

	for(t_cnt i=0; i<size; i++){
		if(s[i]=='1')
			a.num[pos/MOD]^=(I<<(pos%MOD));
		pos--;
	}
	
	return in;
}
*/
istream& operator>>(istream& in, CBinLongWord& a)
{
	string s;
	cin>>s;
	t_cnt pos=0;
	for(t_cnt ii=0; ii<a.len; ii++)
			a.num[ii]=(t_src)0;

	for(t_cnt i=0; i<a.n; i++){
		if(s[s.size()-1-i]=='1')
			a.num[pos/MOD]^=(I<<(pos%MOD));
		pos++;
	}
	
	return in;
}


t_src* CBinLongWord::bin_to_dec(char* p)
 {
	t_len cnt=0;
	while(p[cnt])
		cnt++;

	t_cnt pos=cnt;
	t_cnt r=cnt/MOD;
	if(cnt!=r*MOD)
		r++;

	t_src* result=new t_src[r];
	for(t_cnt h=0; h<r; h++)
		result[h]=(t_src)0;
	pos--;
	for(t_cnt i=0; i<cnt; pos--, i++)
 		if(p[i]=='1') result[pos/MOD]^=(I<<(pos%MOD));
	
 	return result;
 }


t_src* CBinLongWord::bin_to_dec(string& p)
 {
	t_len cnt=p.size();
	t_cnt pos=cnt;
	t_cnt r=cnt/MOD;
	if(cnt!=r*MOD)
		r++;

	t_src* result=new t_src[r];
	for(t_cnt h=0; h<r; h++)
		result[h]=(t_src)0;

	for(t_cnt i=0; i<cnt; pos--, i++)
 		if(p[i]=='1') result[pos/MOD]+=(I<<(pos%MOD));
	
 	return result;
 }



char* CBinLongWord::dec_to_bin()
 {
 	char* bin=new char[n];
 	for(t_cnt i=n-1; i>=0; i--)
 		 bin[n-1-i]=(num[i/MOD]>>(i%MOD))&I?'1':'.';
 	bin[n]='\0';
 
 	return bin;
 }


CBinLongWord& CBinLongWord::operator+=(CBinLongWord& a)
{
	for(t_cnt i=0; i<len; i++)
		num[i]^=a.num[i];

    return *this;
}


CBinLongWord CBinLongWord::operator+(CBinLongWord& a)
{
    CBinLongWord c(a.n);
	for(t_cnt i=0; i<len; i++)
		c.num[i]=num[i]^a.num[i];

    return c;
}



t_len d(CBinLongWord a, CBinLongWord b)
{
	a.weight=0;
	a+=b;
	for(t_cnt i=0; i<a.n; i++)
		a.weight+= t_len((a.num[i/MOD]>>(i%MOD)) & I);

	return a.weight;
}




t_len CBinLongWord::wt()
{
	weight=0;
	for(t_cnt i=0; i<n; i++)
		weight+=t_len((num[i/MOD]>>(i%MOD))&I);

		return weight;
}


/*

void CBinLongWord::next()
{
         t_cnt i=0;
	     t_cnt k=0;
		 for(; (((3UL<<i)&num)!=(1UL<<i))&&(i<n); i++)
		{
            if(((3UL<<i)&num)==(3UL<<i))k++;
        }
     num=(((num>>(i+I))+I)<<(i+I)) | ((I<<k)-I);
        
}
*/

void CBinLongWord::cyclic_shift(t_len k, char where)
{
 t_src tmp=(t_src)0;
 t_cnt p;
 if(n%MOD==0)
	 p=MOD-1;
 else
	 p=n%MOD-1;

 if(where=='r')
	 for(t_cnt x=0; x<k; x++){
		 
		tmp=((num[0]&I)<<p);
		for(t_cnt i=0; i<len-1; i++)
			num[i]=(num[i]>>I)^(num[i+1]<<(MOD-1));
		
		num[len-1]=(num[len-1]>>I)^tmp;
	 }
 else
	  for(t_cnt x=0; x<k; x++){
		 
		tmp=(num[len-1]>>p&I);
		for(t_cnt i=len-1; i>0; i--)
			num[i]=(num[i]<<I)^((num[i-1]>>(MOD-1)&I));

		num[0]=(num[0]<<I)^tmp;
	 }
}


void CBinLongWord::shift(t_len k, char where)
{
 if(where=='r')
	 for(t_cnt x=0; x<k; x++){
		for(t_cnt i=0; i<len-1; i++)
			num[i]=(num[i]>>I)^(num[i+1]<<(MOD-1));
			
		num[len-1]=(num[len-1]>>I);
	 }
 else
	  for(t_cnt x=0; x<k; x++){
		for(t_cnt i=len-1; i>0; i--)
			num[i]=(num[i]<<I)^(((num[i-1]>>(MOD-1))&I));
		num[0]=(num[0]<<I);
	 }
}


void CBinLongWord::bit_set(t_len pos)
{
	num[pos/MOD]|=(I<<(pos%MOD));
}


void CBinLongWord ::bit_clear(t_len pos)
{
	num[pos/MOD]&=~(I<<(pos%MOD));
}


void CBinLongWord ::bit_swap(t_len pos1, t_len pos2)
{
	if(((num[pos1/MOD]>>(pos1%MOD))^(num[pos2/MOD]>>(pos2%MOD)))&I)
	{
		num[pos1/MOD]^=I<<(pos1%MOD);
		num[pos2/MOD]^=I<<(pos2%MOD);
	}
}


t_res CBinLongWord ::is_set(t_len pos)
{
	return t_res((num[pos/MOD]>>pos%MOD)&I);
}


CBinLongWord& CBinLongWord ::operator^=(CBinLongWord& a)
{
	CBinLongWord  ret=*this^a;
	*this=ret;
	return *this;
}


CBinLongWord  CBinLongWord ::operator^(CBinLongWord & a)
{
	t_cnt foo=n*a.n-1;
	CBinLongWord  ret(n*a.n);

	for(t_cnt i=n-1; i>=0; i--)
	{
		if(num[i/MOD]>>(i%MOD)&I)
			for(t_cnt u=a.n-1; u>=0; u--)
			{
				if(a.num[u/MOD]>>(u%MOD)&I)
					ret.num[foo/MOD]^=I<<(foo%MOD);
				foo--;
			}
		else
			foo-=a.n;
	}
	
	return ret;
}



